
namespace System.Collections
{
    /// <summary>
    /// Summary description for UniqueSortedList.
    /// </summary>
    public class UniqueSortedList : IEnumerable
    {
        private static object placeHolder = new object();
        private SortedList list;

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the UniqueSortedList class that is empty,
        /// has the default initial capacity and is sorted according to the IComparable 
        /// interface implemented by each key added to the UniqueSortedList
        /// </summary>
        public UniqueSortedList()
        {
            this.list = new SortedList();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that is empty,
        /// has the specified initial capacity and is sorted according to the IComparable interface implemented by each key added to the SortedList.
        /// </summary>
        /// <param name="capacity"></param>
        public UniqueSortedList(int capacity)
        {
            this.list = new SortedList(capacity);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that is empty,
        /// has the default initial capacity and is sorted according to the IComparable interface passed in.
        /// </summary>
        public UniqueSortedList(IComparer comparer)
        {
            this.list = new SortedList(comparer);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that contains elements copied from the specified dictionary,
        /// has the same initial capacity as the number of elements copied and is sorted according to the IComparable interface implemented by each key.
        /// </summary>
        public UniqueSortedList(IDictionary d)
        {
            this.list = new SortedList(d.Count);
            foreach (DictionaryEntry entry in d)
            {
                Add(entry.Value);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that is empty,
        /// has the specified initial capacity and is sorted according to the IComparable interface passed in.
        /// </summary>
        public UniqueSortedList(IComparer comparer, int capacity)
        {
            this.list = new SortedList(comparer, capacity);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that contains elements copied from the specified dictionary,
        /// has the same initial capacity as the number of elements copied and is sorted according to the specified IComparer interface.
        /// </summary>
        /// <param name="d"></param>
        /// <param name="comparer"></param>
        public UniqueSortedList(IDictionary d, IComparer comparer)
        {
            this.list = new SortedList(comparer);
            foreach (DictionaryEntry entry in d)
            {
                Add(entry.Value);
            }
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets the number of items in the UniqueSortedList
        /// </summary>
        public int Count
        {
            get { return this.list.Count; }
        }

        /// <summary>
        /// Gets all of the items in this as an
        /// object[].
        /// </summary>
        public object[] AllItems
        {
            get
            {
                object[] items = new object[this.list.Count];
                int index = 0;

                foreach (DictionaryEntry entry in this.list)
                {
                    items[index] = entry.Key;
                    ++index;
                }
                return items;
            }
        }

        /// <summary>
        /// Gets the value located at the specified index in the <see cref="UniqueSortedList">UniqueSortedList</see>.
        /// </summary>
        public object this[int index]
        {
            get
            {
                object key = null;

                Check.Require(index, "index", Check.GreaterThanOrEqual(0), Check.LessThan(this.list.Count));

                key = this.list.GetKey(index);

                return key;
            }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Adds the object only if the object isn't contained already
        /// </summary>
        /// <param name="o"></param>
        public void Add(object o)
        {
            // we don't care about the values
            // we only care that we keep the keys unique
            if (!this.list.ContainsKey(o))
            {
                this.list.Add(o, placeHolder);
            }
        }

        /// <summary>
        /// Indicates whether or not the specified object is contained
        /// in the <see cref="UniqueSortedList">UniqueSortedList</see>
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Contains(object key)
        {
            return this.list.ContainsKey(key);
        }

        /// <summary>
        /// Returns an IDictionaryEnumerator that can iterate through the UniqueSortedList.
        /// </summary>
        /// <returns><see cref="IDictionaryEnumerator">IDictionaryEnumerator</see></returns>
        public IEnumerator GetEnumerator()
        {
            return new UniqueSortedListEnumerator(this);
        }
        #endregion

        #region UniqueSortedListEnumerator
        /// <summary>
        /// Implements an enumerator for the UniqueSortedList
        /// </summary>
        private class UniqueSortedListEnumerator : IEnumerator
        {
            UniqueSortedList sortedList;
            object current;
            int internalIndex;

            public UniqueSortedListEnumerator(UniqueSortedList list)
            {
                this.sortedList = list;
                Reset();
            }
            #region IEnumerator Members

            /// <summary>
            /// Resets the enumerator to point to the first item
            /// in the list.
            /// </summary>
            public void Reset()
            {
                if (this.sortedList != null && this.sortedList.list.Count > 0)
                {
                    this.current = this.sortedList[0];
                    this.internalIndex = 0;
                }
            }

            /// <summary>
            /// Gets the current object in the list
            /// </summary>
            public object Current
            {
                get { return this.current; }
            }

            /// <summary>
            /// Moves the current object in the list to the next
            /// if there are more objects in the list.
            /// </summary>
            /// <returns>false if there are no more objects in the list, true otherwise</returns>
            public bool MoveNext()
            {
                if (this.internalIndex >= this.sortedList.Count)
                {
                    return false;
                }
                this.current = this.sortedList[this.internalIndex];
                ++this.internalIndex;

                return true;
            }

            #endregion
        }
        #endregion
    }
}
